// ============================================================================
//
// Copyright (C) 2006-2007 Dengues
//
// Google Group: http://groups.google.com/group/dengues
// QQ Group: 24885404
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
//
// ============================================================================
package org.dengues.warehouse.viewers;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import org.dengues.core.metadata.MetadataTable;
import org.dengues.core.resource.WarehouseResourceFactory;
import org.dengues.core.warehouse.ENavNodeType;
import org.dengues.core.warehouse.ENodeCategoryName;
import org.dengues.core.warehouse.IWarehouseNode;
import org.dengues.core.warehouse.IWarehouseObject;
import org.dengues.core.warehouse.IWarehouseViewFactory;
import org.dengues.model.database.DatabaseDiagram;
import org.dengues.warehouse.models.WarehouseNode;
import org.dengues.warehouse.models.WarehouseObject;
import org.eclipse.core.resources.IFolder;
import org.eclipse.core.runtime.IPath;
import org.eclipse.jface.util.LocalSelectionTransfer;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.StructuredSelection;
import org.eclipse.jface.viewers.TreeSelection;
import org.eclipse.jface.viewers.TreeViewer;
import org.eclipse.jface.viewers.ViewerDropAdapter;
import org.eclipse.swt.dnd.DND;
import org.eclipse.swt.dnd.DragSourceAdapter;
import org.eclipse.swt.dnd.DragSourceEvent;
import org.eclipse.swt.dnd.Transfer;
import org.eclipse.swt.dnd.TransferData;

/**
 * Qiang.Zhang.Adolf@gmail.com class global comment. Detailled comment <br/>
 * 
 * $Id: Dengues.epf 2007-12-16 qiang.zhang $
 * 
 */
public class WarehouseViewFactory implements IWarehouseViewFactory {

    /**
     * Qiang.Zhang.Adolf@gmail.com WarehouseViewFactory constructor comment.
     */
    public WarehouseViewFactory() {
    }

    /*
     * (non-Javadoc)
     * 
     * @see org.dengues.core.warehouse.IWarehouseViewFactory#getWarehouseTables()
     */
    public Map<String, MetadataTable> getWarehouseTables() {
        return WarehouseViewProvider.getWarehouseTables();
    }

    /*
     * (non-Javadoc)
     * 
     * @see org.dengues.core.warehouse.IWarehouseViewFactory#getObjectsFromEMF(org.dengues.core.warehouse.ENodeCategoryName,
     * org.eclipse.core.runtime.IPath)
     */
    public List<IWarehouseObject> getObjectsFromEMF(ENodeCategoryName name, IPath path) {
        List<IWarehouseObject> list = new ArrayList<IWarehouseObject>();
        List<Object> processFromEMF = WarehouseResourceFactory.getObjectFromEMF(name, path);
        for (Object type : processFromEMF) {
            if (!(type instanceof IFolder)) {
                WarehouseObject object = new WarehouseObject(type);
                object.setCategoryName(name);
                object.setNodeType(ENavNodeType.ELEMENT);
                list.add(object);
            }
        }
        return list;
    }

    /*
     * (non-Javadoc)
     * 
     * @see org.dengues.core.warehouse.IWarehouseViewFactory#createWarehouseNodeFromEMF(org.dengues.core.warehouse.ENodeCategoryName,
     * org.dengues.core.warehouse.IWarehouseNode, java.lang.Object)
     */
    public IWarehouseNode createWarehouseNodeFromEMF(ENodeCategoryName name, IWarehouseNode parent, Object processType) {
        WarehouseNode node = null;
        WarehouseObject object = new WarehouseObject(processType);
        object.setCategoryName(name);
        object.setNodeType(ENavNodeType.ELEMENT);
        node = new WarehouseNode(object, parent, ENavNodeType.ELEMENT);
        node.setBin(false);
        // node.setLabel(processType.getName());
        node.setCategoryName(name);
        return node;
    }

    /**
     * Qiang.Zhang.Adolf@gmail.com Comment method "initDragAndDrop".
     * 
     * @param viewer
     */
    public static void initDragAndDrop(final TreeViewer viewer) {
        int ops = DND.DROP_COPY | DND.DROP_MOVE;
        Transfer[] transfers = new Transfer[] { LocalSelectionTransfer.getTransfer() };
        viewer.addDragSupport(ops, transfers, new DragSourceAdapter() {

            private static final long FFFFFFFFL = 0xFFFFFFFFL;

            /*
             * (non-Javadoc)
             * 
             * @see org.eclipse.swt.dnd.DragSourceAdapter#dragStart(org.eclipse.swt.dnd.DragSourceEvent)
             */
            @Override
            public void dragStart(DragSourceEvent event) {
                ISelection selection = viewer.getSelection();
                LocalSelectionTransfer.getTransfer().setSelection(selection);
                LocalSelectionTransfer.getTransfer().setSelectionSetTime(event.time & FFFFFFFFL);
            }

            /*
             * (non-Javadoc)
             * 
             * @see org.eclipse.swt.dnd.DragSourceAdapter#dragFinished(org.eclipse.swt.dnd.DragSourceEvent)
             */
            @Override
            public void dragFinished(DragSourceEvent event) {
                WarehouseView.root = new WarehouseNode(null, null, ENavNodeType.SYSTEM_FOLDER);
                viewer.refresh();
                viewer.setSelection(new TreeSelection());
                LocalSelectionTransfer.getTransfer().setSelection(null);
                LocalSelectionTransfer.getTransfer().setSelectionSetTime(0);
            }

            /*
             * (non-Javadoc)
             * 
             * @see org.eclipse.swt.dnd.DragSourceAdapter#dragSetData(org.eclipse.swt.dnd.DragSourceEvent)
             */
            @Override
            public void dragSetData(DragSourceEvent event) {
                event.data = LocalSelectionTransfer.getTransfer().getSelection();
            }

        });

        viewer.addDropSupport(ops, transfers, new ViewerDropAdapter(viewer) {

            /*
             * (non-Javadoc)
             * 
             * @see org.eclipse.ui.part.PluginDropAdapter#performDrop(java.lang.Object)
             */
            @Override
            public boolean performDrop(Object data) {
                int operation = getCurrentOperation();
                WarehouseNode targetNode = (WarehouseNode) getCurrentTarget();
                boolean toReturn = true;
                for (Object obj : ((StructuredSelection) data).toArray()) {
                    if (obj instanceof WarehouseNode) {
                        switch (operation) {
                        case DND.DROP_COPY:
                            executeCopy((WarehouseNode) obj, targetNode);
                            break;
                        default:
                            executeMove((WarehouseNode) obj, targetNode);
                        }
                    }
                }
                return toReturn;
            }

            /*
             * (non-Javadoc)
             * 
             * @see org.eclipse.ui.part.PluginDropAdapter#validateDrop(java.lang.Object, int,
             * org.eclipse.swt.dnd.TransferData)
             */
            @Override
            public boolean validateDrop(Object target, int operation, TransferData transferType) {
                boolean isValidate = false;
                ISelection selection = getViewer().getSelection();
                if (selection instanceof StructuredSelection) {
                    StructuredSelection structuredSelection = (StructuredSelection) selection;
                    for (Object sel : structuredSelection.toList()) {
                        if (sel instanceof WarehouseNode) {
                            switch (operation) {
                            case DND.DROP_COPY:
                                isValidate = validateCopy((WarehouseNode) sel, (WarehouseNode) target);
                                break;
                            default:
                                isValidate = validateMove((WarehouseNode) sel, (WarehouseNode) target);
                            }
                        }
                    }
                }
                return isValidate;
            }

        });

    }

    /**
     * Qiang.Zhang.Adolf@gmail.com Comment method "executeMove".
     * 
     * @param source
     * @param target
     */
    protected static void executeMove(WarehouseNode source, WarehouseNode target) {
        if (target.getCategoryName().equals(ENodeCategoryName.BIN)) {
            WarehouseResourceFactory.deleteObjectLogical(source.getObject());
        } else if (target.getNodeType() != ENavNodeType.ELEMENT) {
            if (source.isBin()) {
                WarehouseResourceFactory.restoreObjectLogical(source.getObject());
            }
            WarehouseResourceFactory.moveObjectPhysical(source, target.getWarehousePath());
        }
    }

    /**
     * Qiang.Zhang.Adolf@gmail.com Comment method "executeCopy".
     * 
     * @param source
     * @param target
     */
    protected static void executeCopy(WarehouseNode source, WarehouseNode target) {
        if ((target.getNodeType() == ENavNodeType.SIMPLE_FOLDER) || target.getNodeType() == ENavNodeType.SYSTEM_FOLDER) {
            WarehouseResourceFactory.copyObjectPhysical(source, target.getWarehousePath());
        }
    }

    /**
     * Qiang.Zhang.Adolf@gmail.com Comment method "validateCopy".
     * 
     * @param source
     * @param target
     * @return
     */
    protected static boolean validateCopy(WarehouseNode source, WarehouseNode target) {
        if (source == null) {
            return false;
        }
        if (target == null) {
            return false;
        }
        if (source.equals(target)) {
            return false;
        }
        IPath seg = source.getWarehousePath();
        if (seg.equals(target.getWarehousePath())) {
            return false;
        }
        ENodeCategoryName sourceCategoryName = source.getCategoryName();
        ENodeCategoryName targetCategoryName = target.getCategoryName();
        if (targetCategoryName == ENodeCategoryName.BIN || source.isBin() || sourceCategoryName == ENodeCategoryName.BLOCKS) {
            return false;
        }
        if (targetCategoryName == sourceCategoryName && source.getNodeType() == ENavNodeType.ELEMENT
                && ((target.getNodeType() == ENavNodeType.SIMPLE_FOLDER) || target.getNodeType() == ENavNodeType.SYSTEM_FOLDER)) {
            return true;
        }
        return false;
    }

    /**
     * Qiang.Zhang.Adolf@gmail.com Comment method "validateMove".
     * 
     * @param source
     * @param target
     * @return
     */
    protected static boolean validateMove(WarehouseNode source, WarehouseNode target) {
        if (source == null) {
            return false;
        }
        if (target == null) {
            return false;
        }
        if (source.equals(target)) {
            return false;
        }
        IPath seg = source.getWarehousePath();
        if (seg.equals(target.getWarehousePath())) {
            return false;
        }
        ENodeCategoryName sourceCategoryName = source.getCategoryName();
        ENodeCategoryName targetCategoryName = target.getCategoryName();
        if (sourceCategoryName == ENodeCategoryName.BLOCKS) {
            return false;
        }
        if (targetCategoryName == ENodeCategoryName.BIN && !source.isBin()) {
            return true;
        }
        if (targetCategoryName == sourceCategoryName && source.getNodeType() == ENavNodeType.ELEMENT
                && target.getNodeType() != ENavNodeType.ELEMENT) {
            return true;
        }
        return false;
    }

    /*
     * (non-Javadoc)
     * 
     * @see org.dengues.core.warehouse.IWarehouseViewFactory#getWarehouseQueries()
     */
    public Map<String, DatabaseDiagram> getWarehouseQueries() {
        return WarehouseViewProvider.getWarehouseQueries();
    }
}
